package com.zed.infrastructure.persistence.mybatis.plus.core;

import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.core.field.FieldQueryBuilder;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryCondition;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Row;
import com.zed.api.common.ApplicationContextAwareExtend;
import com.zed.api.common.ApplicationContextSupport;
import org.apache.ibatis.cursor.Cursor;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;

/**
 * {@link com.mybatisflex.core.BaseMapper}包装类
 *
 * @author Zed
 */
class BaseMapperWrapper<M> extends ApplicationContextSupport implements BaseMapper<M> {

    private BaseMapper<M> baseMapper;


    BaseMapperWrapper(BaseMapper<M> baseMapper) {
        this.baseMapper = Objects.requireNonNull(baseMapper, "\"baseMapper\" cannot be null.");
    }

    @Override
    public int insert(M entity) {
        return this.baseMapper.insert(entity);
    }

    @Override
    public int insertSelective(M entity) {
        return this.baseMapper.insertSelective(entity);
    }

    @Override
    public int insert(M m, boolean b) {
        return this.baseMapper.insert(m, b);
    }

    @Override
    public int insertWithPk(M entity) {
        return this.baseMapper.insertWithPk(entity);
    }

    @Override
    public int insertSelectiveWithPk(M entity) {
        return this.baseMapper.insertSelectiveWithPk(entity);
    }

    @Override
    public int insertWithPk(M m, boolean b) {
        return this.baseMapper.insertWithPk(m, b);
    }

    @Override
    public int insertBatch(List<M> list) {
        return this.baseMapper.insertBatch(list);
    }

    @Override
    public int insertBatch(List<M> entities, int size) {
        return this.baseMapper.insertBatch(entities, size);
    }

    @Override
    public int insertOrUpdate(M entity) {
        return this.baseMapper.insertOrUpdate(entity);
    }

    @Override
    public int insertOrUpdateSelective(M entity) {
        return this.baseMapper.insertOrUpdateSelective(entity);
    }

    @Override
    public int insertOrUpdate(M entity, boolean ignoreNulls) {
        return this.baseMapper.insertOrUpdate(entity, ignoreNulls);
    }

    @Override
    public int delete(M entity) {
        return this.baseMapper.delete(entity);
    }

    @Override
    public int deleteById(Serializable serializable) {
        return this.baseMapper.deleteById(serializable);
    }

    @Override
    public int deleteBatchByIds(Collection<? extends Serializable> collection) {
        return this.baseMapper.deleteBatchByIds(collection);
    }

    @Override
    public int deleteBatchByIds(List<? extends Serializable> ids, int size) {
        return this.baseMapper.deleteBatchByIds(ids, size);
    }

    @Override
    public int deleteByMap(Map<String, Object> whereConditions) {
        return this.baseMapper.deleteByMap(whereConditions);
    }

    @Override
    public int deleteByCondition(QueryCondition whereConditions) {
        return this.baseMapper.deleteByCondition(whereConditions);
    }

    @Override
    public int deleteByQuery(QueryWrapper queryWrapper) {
        return this.baseMapper.deleteByQuery(queryWrapper);
    }

    @Override
    public int update(M entity) {
        return this.baseMapper.update(entity);
    }

    @Override
    public int update(M m, boolean b) {
        return this.baseMapper.update(m, b);
    }

    @Override
    public int updateByMap(M entity, Map<String, Object> whereConditions) {
        return this.baseMapper.updateByMap(entity, whereConditions);
    }

    @Override
    public int updateByMap(M entity, boolean ignoreNulls, Map<String, Object> whereConditions) {
        return this.baseMapper.updateByMap(entity, ignoreNulls, whereConditions);
    }

    @Override
    public int updateByCondition(M entity, QueryCondition whereConditions) {
        return this.baseMapper.updateByCondition(entity, whereConditions);
    }

    @Override
    public int updateByCondition(M entity, boolean ignoreNulls, QueryCondition whereConditions) {
        return this.baseMapper.updateByCondition(entity, ignoreNulls, whereConditions);
    }

    @Override
    public int updateByQuery(M entity, QueryWrapper queryWrapper) {
        return this.baseMapper.updateByQuery(entity, queryWrapper);
    }

    @Override
    public int updateByQuery(M m, boolean b, QueryWrapper queryWrapper) {
        return this.baseMapper.updateByQuery(m, b, queryWrapper);
    }

    @Override
    public M selectOneByEntityId(M entity) {
        M m = this.baseMapper.selectOneByEntityId(entity);
        ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        return m;
    }

    @Override
    public M selectOneById(Serializable serializable) {
        M m = this.baseMapper.selectOneById(serializable);
        ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        return m;
    }

    @Override
    public M selectOneByMap(Map<String, Object> whereConditions) {
        M m = this.baseMapper.selectOneByMap(whereConditions);
        ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        return m;
    }

    @Override
    public M selectOneByCondition(QueryCondition whereConditions) {
        M m = this.baseMapper.selectOneByCondition(whereConditions);
        ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        return m;
    }

    @Override
    public M selectOneByQuery(QueryWrapper queryWrapper) {
        M m = this.baseMapper.selectOneByQuery(queryWrapper);
        ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        return m;
    }

    @Override
    public <R> R selectOneByQueryAs(QueryWrapper queryWrapper, Class<R> asType) {
        R r = this.baseMapper.selectOneByQueryAs(queryWrapper, asType);
        ApplicationContextAwareExtend.tryToBind(r, this.getContext());
        return r;
    }

    @Override
    public M selectOneWithRelationsByMap(Map<String, Object> whereConditions) {
        M m = this.baseMapper.selectOneWithRelationsByMap(whereConditions);
        ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        return m;
    }

    @Override
    public M selectOneWithRelationsByCondition(QueryCondition whereConditions) {
        M m = this.baseMapper.selectOneWithRelationsByCondition(whereConditions);
        ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        return m;
    }

    @Override
    public M selectOneWithRelationsByQuery(QueryWrapper queryWrapper) {
        M m = this.baseMapper.selectOneWithRelationsByQuery(queryWrapper);
        ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        return m;
    }

    @Override
    public M selectOneWithRelationsById(Serializable id) {
        M m = this.baseMapper.selectOneWithRelationsById(id);
        ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        return m;
    }

    @Override
    public <R> R selectOneWithRelationsByIdAs(Serializable id, Class<R> asType) {
        R r = this.baseMapper.selectOneWithRelationsByIdAs(id, asType);
        ApplicationContextAwareExtend.tryToBind(r, this.getContext());
        return r;
    }

    @Override
    public <R> R selectOneWithRelationsByQueryAs(QueryWrapper queryWrapper, Class<R> asType) {
        R r = this.baseMapper.selectOneWithRelationsByQueryAs(queryWrapper, asType);
        ApplicationContextAwareExtend.tryToBind(r, this.getContext());
        return r;
    }

    @Override
    public List<M> selectListByIds(Collection<? extends Serializable> collection) {
        List<M> list = this.baseMapper.selectListByIds(collection);

        for (M m : list) {
            ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        }

        return list;
    }

    @Override
    public List<M> selectListByMap(Map<String, Object> whereConditions) {
        List<M> list = this.baseMapper.selectListByMap(whereConditions);

        for (M m : list) {
            ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        }

        return list;
    }

    @Override
    public List<M> selectListByMap(Map<String, Object> whereConditions, Long count) {
        List<M> list = this.baseMapper.selectListByMap(whereConditions, count);

        for (M m : list) {
            ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        }

        return list;
    }

    @Override
    public List<M> selectListByCondition(QueryCondition whereConditions) {
        List<M> list = this.baseMapper.selectListByCondition(whereConditions);

        for (M m : list) {
            ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        }

        return list;
    }

    @Override
    public List<M> selectListByCondition(QueryCondition whereConditions, Long count) {
        List<M> list = this.baseMapper.selectListByCondition(whereConditions, count);

        for (M m : list) {
            ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        }

        return list;

    }

    @Override
    public List<M> selectListByQuery(QueryWrapper queryWrapper) {

        List<M> list = this.baseMapper.selectListByQuery(queryWrapper);

        for (M m : list) {
            ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        }

        return list;
    }

    @Override
    public List<M> selectListByQuery(QueryWrapper queryWrapper, Consumer<FieldQueryBuilder<M>>... consumers) {
        List<M> list = this.baseMapper.selectListByQuery(queryWrapper, consumers);

        for (M m : list) {
            ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        }

        return list;

    }

    @Override
    public Cursor<M> selectCursorByQuery(QueryWrapper queryWrapper) {
        return this.baseMapper.selectCursorByQuery(queryWrapper);
    }

    @Override
    public List<Row> selectRowsByQuery(QueryWrapper queryWrapper) {
        return this.baseMapper.selectRowsByQuery(queryWrapper);
    }

    @Override
    public <R> List<R> selectListByQueryAs(QueryWrapper queryWrapper, Class<R> asType) {
        List<R> rs = this.baseMapper.selectListByQueryAs(queryWrapper, asType);

        for (R m : rs) {
            ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        }

        return rs;

    }

    @Override
    public <R> List<R> selectListByQueryAs(QueryWrapper queryWrapper, Class<R> asType, Consumer<FieldQueryBuilder<R>>... consumers) {

        List<R> rs = this.baseMapper.selectListByQueryAs(queryWrapper, asType, consumers);

        for (R m : rs) {
            ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        }

        return rs;
    }

    @Override
    public List<M> selectListWithRelationsByQuery(QueryWrapper queryWrapper) {
        List<M> list = this.baseMapper.selectListWithRelationsByQuery(queryWrapper);

        for (M m : list) {
            ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        }

        return list;

    }

    @Override
    public <R> List<R> selectListWithRelationsByQueryAs(QueryWrapper queryWrapper, Class<R> asType) {

        List<R> list = this.baseMapper.selectListWithRelationsByQueryAs(queryWrapper, asType);

        for (R m : list) {
            ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        }

        return list;

    }

    @Override
    public <R> List<R> selectListWithRelationsByQueryAs(QueryWrapper queryWrapper, Class<R> asType, Consumer<FieldQueryBuilder<R>>... consumers) {

        List<R> list = this.baseMapper.selectListWithRelationsByQueryAs(queryWrapper, asType, consumers);

        for (R m : list) {
            ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        }

        return list;
    }

    @Override
    public List<M> selectAll() {
        List<M> list = this.baseMapper.selectAll();

        for (M m : list) {
            ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        }

        return list;
    }

    @Override
    public List<M> selectAllWithRelations() {
        List<M> list = this.baseMapper.selectAllWithRelations();

        for (M m : list) {
            ApplicationContextAwareExtend.tryToBind(m, this.getContext());
        }

        return list;
    }

    @Override
    public Object selectObjectByQuery(QueryWrapper queryWrapper) {
        Object o = this.baseMapper.selectObjectByQuery(queryWrapper);
        ApplicationContextAwareExtend.tryToBind(o, this.getContext());
        return o;

    }

    @Override
    public <R> R selectObjectByQueryAs(QueryWrapper queryWrapper, Class<R> asType) {
        R r = this.baseMapper.selectObjectByQueryAs(queryWrapper, asType);

        ApplicationContextAwareExtend.tryToBind(r, this.getContext());

        return r;
    }

    @Override
    public List<Object> selectObjectListByQuery(QueryWrapper queryWrapper) {

        List<Object> objects = this.baseMapper.selectObjectListByQuery(queryWrapper);

        for (Object object : objects) {
            ApplicationContextAwareExtend.tryToBind(object, this.getContext());
        }

        return null;
    }

    @Override
    public <R> List<R> selectObjectListByQueryAs(QueryWrapper queryWrapper, Class<R> asType) {
        List<R> rs = this.baseMapper.selectObjectListByQueryAs(queryWrapper, asType);

        for (R r : rs) {
            ApplicationContextAwareExtend.tryToBind(r, this.getContext());
        }

        return rs;

    }

    @Override
    public long selectCountByQuery(QueryWrapper queryWrapper) {
        return this.baseMapper.selectCountByQuery(queryWrapper);
    }

    @Override
    public long selectCountByCondition(QueryCondition whereConditions) {
        return this.baseMapper.selectCountByCondition(whereConditions);
    }

    @Override
    public Page<M> paginate(Number pageNumber, Number pageSize, QueryWrapper queryWrapper) {
        Page<M> paginate = this.baseMapper.paginate(pageNumber, pageSize, queryWrapper);

        for (M record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }

        return paginate;
    }

    @Override
    public Page<M> paginateWithRelations(Number pageNumber, Number pageSize, QueryWrapper queryWrapper) {
        Page<M> paginate = this.baseMapper.paginateWithRelations(pageNumber, pageSize, queryWrapper);

        for (M record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }

        return paginate;
    }

    @Override
    public Page<M> paginate(Number pageNumber, Number pageSize, QueryCondition whereConditions) {

        Page<M> paginate = this.baseMapper.paginate(pageNumber, pageSize, whereConditions);

        for (M record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }

        return paginate;

    }

    @Override
    public Page<M> paginateWithRelations(Number pageNumber, Number pageSize, QueryCondition whereConditions) {

        Page<M> paginate = this.baseMapper.paginateWithRelations(pageNumber, pageSize, whereConditions);

        for (M record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }

        return paginate;

    }

    @Override
    public Page<M> paginate(Number pageNumber, Number pageSize, Number totalRow, QueryWrapper queryWrapper) {

        Page<M> paginate = this.baseMapper.paginate(pageNumber, pageSize, totalRow, queryWrapper);

        for (M record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }

        return paginate;
    }

    @Override
    public Page<M> paginateWithRelations(Number pageNumber, Number pageSize, Number totalRow, QueryWrapper queryWrapper) {


        Page<M> paginate = this.baseMapper.paginateWithRelations(pageNumber, pageSize, totalRow, queryWrapper);

        for (M record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }

        return paginate;
    }

    @Override
    public Page<M> paginate(Number pageNumber, Number pageSize, Number totalRow, QueryCondition whereConditions) {

        Page<M> paginate = this.baseMapper.paginate(pageNumber, pageSize, totalRow, whereConditions);

        for (M record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }

        return paginate;

    }

    @Override
    public Page<M> paginateWithRelations(Number pageNumber, Number pageSize, Number totalRow, QueryCondition whereConditions) {

        Page<M> paginate = this.baseMapper.paginateWithRelations(pageNumber, pageSize, totalRow, whereConditions);

        for (M record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }

        return paginate;
    }

    @Override
    public Page<M> paginate(Page<M> page, QueryWrapper queryWrapper) {


        Page<M> paginate = this.baseMapper.paginate(page, queryWrapper);

        for (M record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }

        return paginate;

    }

    @Override
    public Page<M> paginate(Page<M> page, QueryWrapper queryWrapper, Consumer<FieldQueryBuilder<M>>... consumers) {


        Page<M> paginate = this.baseMapper.paginate(page, queryWrapper, consumers);

        for (M record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }

        return paginate;

    }

    @Override
    public Page<M> paginateWithRelations(Page<M> page, QueryWrapper queryWrapper) {


        Page<M> paginate = this.baseMapper.paginateWithRelations(page, queryWrapper);

        for (M record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }

        return paginate;

    }

    @Override
    public Page<M> paginateWithRelations(Page<M> page, QueryWrapper queryWrapper, Consumer<FieldQueryBuilder<M>>... consumers) {


        Page<M> paginate = this.baseMapper.paginateWithRelations(page, queryWrapper, consumers);

        for (M record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }

        return paginate;
    }

    @Override
    public <R> Page<R> paginateAs(Number pageNumber, Number pageSize, QueryWrapper queryWrapper, Class<R> asType) {

        Page<R> paginate = this.baseMapper.paginateAs(pageNumber, pageSize, queryWrapper, asType);

        for (R record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }

        return paginate;
    }

    @Override
    public <R> Page<R> paginateAs(Number pageNumber, Number pageSize, Number totalRow, QueryWrapper queryWrapper, Class<R> asType) {

        Page<R> paginate = this.baseMapper.paginateAs(pageNumber, pageSize, totalRow, queryWrapper, asType);

        for (R record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }

        return paginate;

    }

    @Override
    public <R> Page<R> paginateAs(Page<R> page, QueryWrapper queryWrapper, Class<R> asType) {

        Page<R> paginate = this.baseMapper.paginateAs(page, queryWrapper, asType);

        for (R record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }

        return paginate;

    }

    @Override
    public <R> Page<R> paginateAs(Page<R> page, QueryWrapper queryWrapper, Class<R> asType, Consumer<FieldQueryBuilder<R>>... consumers) {
        Page<R> paginate = this.baseMapper.paginateAs(page, queryWrapper, asType, consumers);

        for (R record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }

        return paginate;
    }

    @Override
    public <R> Page<R> paginateWithRelationsAs(Number pageNumber, Number pageSize, QueryWrapper queryWrapper, Class<R> asType) {
        Page<R> paginate = this.baseMapper.paginateWithRelationsAs(pageNumber, pageSize, queryWrapper, asType);

        for (R record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }

        return paginate;
    }

    @Override
    public <R> Page<R> paginateWithRelationsAs(Number pageNumber, Number pageSize, Number totalRow, QueryWrapper queryWrapper, Class<R> asType) {
        Page<R> paginate = this.baseMapper.paginateWithRelationsAs(pageNumber, pageSize, totalRow, queryWrapper, asType);

        for (R record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }

        return paginate;
    }

    @Override
    public <R> Page<R> paginateWithRelationsAs(Page<R> page, QueryWrapper queryWrapper, Class<R> asType) {

        Page<R> paginate = this.baseMapper.paginateWithRelationsAs(page, queryWrapper, asType);

        for (R record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }

        return paginate;

    }

    @Override
    public <R> Page<R> paginateWithRelationsAs(Page<R> page, QueryWrapper queryWrapper, Class<R> asType, Consumer<FieldQueryBuilder<R>>... consumers) {

        Page<R> paginate = this.baseMapper.paginateWithRelationsAs(page, queryWrapper, asType, consumers);

        for (R record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }

        return paginate;

    }

    @Override
    public <E> Page<E> xmlPaginate(String dataSelectId, Page<E> page, QueryWrapper queryWrapper) {

        Page<E> paginate = this.baseMapper.xmlPaginate(dataSelectId, page, queryWrapper);

        for (E record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }

        return paginate;
    }

    @Override
    public <E> Page<E> xmlPaginate(String dataSelectId, Page<E> page, Map<String, Object> otherParams) {
        Page<E> paginate = this.baseMapper.xmlPaginate(dataSelectId, page, otherParams);

        for (E record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }
        return paginate;
    }

    @Override
    public <E> Page<E> xmlPaginate(String dataSelectId, Page<E> page, QueryWrapper queryWrapper, Map<String, Object> otherParams) {

        Page<E> paginate = this.baseMapper.xmlPaginate(dataSelectId, page, queryWrapper, otherParams);

        for (E record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }
        return paginate;
    }

    @Override
    public <E> Page<E> xmlPaginate(String dataSelectId, String countSelectId, Page<E> page, QueryWrapper queryWrapper, Map<String, Object> otherParams) {

        Page<E> paginate = this.baseMapper.xmlPaginate(dataSelectId, countSelectId, page, queryWrapper, otherParams);

        for (E record : paginate.getRecords()) {
            ApplicationContextAwareExtend.tryToBind(record, this.getContext());
        }
        return paginate;
    }
}
